package com.bolehui.base.intercetor;

import com.bolehui.base.annotation.AutoFill;
import com.bolehui.base.enums.StatusTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.Properties;

/**
 * @author chendongjie     email:chendongjie@gz.iscas.ac.cn
 * @version 1.0
 * @ClassName AutoFillInterceptor
 * @Description 自动填充公共字段拦截器
 * @createTime 2024/11/29 10:50
 * Copyright (C) 2021-2022 CASEEDER, All Rights Reserved.
 * 注意：本内容仅限于内部传阅，禁止外泄以及用于其他的商业目的
 */
@Slf4j
@Intercepts(
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
)
public class AutoFillInterceptor implements Interceptor {

    /**
     * {@link AutoFill}注解对象
     */
    private static final Class<AutoFill> AUTO_FILL = AutoFill.class;

    /**
     * 创建者学号公共字段名
     */
    private static final String CREATE_BY = "createBy";

    /**
     * 创建时间公共字段名
     */
    private static final String CREATE_TIME = "createTime";

    /**
     * 修改者学号公共字段名
     */
    private static final String UPDATE_BY = "updateBy";

    /**
     * 修改时间公共字段名
     */
    private static final String UPDATE_TIME = "updateTime";

    /**
     * 状态
     */
    private static final String STATUS = "status";

    /**
     * 根据sql操作类型 填充公共字段
     *
     * @param sqlCommandType sql操作类型
     * @param fields         传入对象的所有字段
     * @param object         传入对象
     * @throws IllegalAccessException 公共字段无法填充抛出此异常
     */
    private static void autoFillFields(SqlCommandType sqlCommandType, Field[] fields, Object object) throws IllegalAccessException{
        for (Field field : fields) {
            // 判断字段是否被AutoFill注解标识并且是指定sql操作才进行共字段的填充
            if (field.isAnnotationPresent(AUTO_FILL)) {
                field.setAccessible(true);
                for (SqlCommandType type : field.getAnnotation(AUTO_FILL).value()) {
                    if (sqlCommandType.equals(type)) {
                        switch (field.getName()) {
                            // Todo 自动填充创建人 修改人 完善获取当前登录人id
//                            case CREATE_BY, UPDATE_BY -> field.set(object, LoginUtils.getLoginUserId());
                            case CREATE_TIME, UPDATE_TIME -> field.set(object, LocalDateTime.now());
                            case STATUS -> field.set(object, StatusTypeEnum.normal.name());
                        }
                    }
                }
            }
        }
    }


    /**
     * 自动填充公共字段
     *
     * @param invocation 被拦截的方法的详细信息
     * @return 拦截处理后的返回值
     * @throws Throwable 被拦截方法运行出现异常抛出异常
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取被拦截方法的sql操作类型sqlCommandType 传入的对象object 传入对象的字段fields
        Object[] args = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement) args[0];
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        Object object = args[1];
        Field[] fields = object.getClass()
                .getSuperclass()
                .getDeclaredFields();

        try {
            // 只有插入和新增操作会进行公共字段填充操作
            if (sqlCommandType == SqlCommandType.INSERT) {
                autoFillFields(SqlCommandType.INSERT, fields, object);
            } else if (sqlCommandType == SqlCommandType.UPDATE) {
                autoFillFields(SqlCommandType.UPDATE, fields, object);
            }
        } catch (IllegalAccessException e) {
            log.error("自动填充公共字段失败", e);
        }
        // 调用原来的方法
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object o) {
        return null;
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
